package com.chang.gulimall_auth.controller;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONUtil;
import com.chang.common.constant.AuthServerConstant;
import com.chang.common.exception.BizCodeEnum;
import com.chang.common.utils.R;
import com.chang.common.vo.MemberResponseVo;
import com.chang.gulimall_auth.feign.MemberFeignServer;
import com.chang.gulimall_auth.feign.ThirdFeignServer;
import com.chang.gulimall_auth.vo.UserLoginVo;
import com.chang.gulimall_auth.vo.UserRegisterVo;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpSession;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author: changzhenxi
 * @date: 2024年11月26日 11:15
 * @Version: 1.0
 * @description:
 */
@Slf4j
@Controller
public class LoginController {

    @Resource
    StringRedisTemplate stringRedisTemplate;

    @Resource
    ThirdFeignServer thirdFeignServer;

    @Resource
    MemberFeignServer memberFeignServer;

    @ResponseBody
    @GetMapping("sms/sendCode")
    public R sendCode(@RequestParam String email) {

        // TODO 接口防刷

        // 新方法 直接获取redis存储数据的的过期时间
        Long expire = stringRedisTemplate.getExpire(AuthServerConstant.SMS_CODE_CACHE_PREFIX + email);
        if (expire != null && 600 - expire < 60) {
            return R.error(BizCodeEnum.VALID_SMS_CODE_EXCEPTION.getCode(), BizCodeEnum.VALID_SMS_CODE_EXCEPTION.getMsg());
        }


        // 老方法 利用系统的时间进行判断,可能存在时区不一致导致的使用问题 并且同样都只请求一遍redis服务器 老方法更繁琐
        /*String oldCode = stringRedisTemplate.opsForValue().get(AuthServerConstant.SMS_CODE_CACHE_PREFIX + email);
        long oldTime = 0;
        if (oldCode != null) {
            oldTime = Long.parseLong(oldCode.split("_")[1]);
        }
        // 60秒内不能再发
        if (System.currentTimeMillis()-oldTime<60000){
            return R.error(BizCodeEnum.VALID_SMS_CODE_EXCEPTION.getCode(),BizCodeEnum.VALID_SMS_CODE_EXCEPTION.getMsg());
        }*/

        String code = RandomUtil.randomNumbers(6);
        // redis 缓存验证码 十分钟过期
        stringRedisTemplate.opsForValue().set(AuthServerConstant.SMS_CODE_CACHE_PREFIX + email, code, 10, TimeUnit.MINUTES);

        thirdFeignServer.sendEmail(email, code);
        return R.ok();
    }

    // TODO 重定向携带数据 利用session原理 将数据携带到session中 只要跳到下一个页面,取出这个数据以后,session中的数据就会删掉 但是用到session之后在分布式环境会有问题 此处待完善
    // RedirectAttributes 模拟重定向携带数据 如果只是用model
    // forward 请求跳转到其他页面时默认使用post请求,如果跳转到一个get请求的接口就会报错  Request method 'POST' is not supported
    @PostMapping("/register")
    public String register(@Valid UserRegisterVo userRegisterVo, BindingResult bindingResult, RedirectAttributes attributes) {
        Map<String, Object> errorMap = new HashMap<>();
        if (bindingResult.hasErrors()) { // 校验出错 原地tp
            log.info("注册出错........");
            errorMap = bindingResult.getFieldErrors()
                    .stream()
                    .collect(Collectors.toMap(FieldError::getField, fieldError -> fieldError.getDefaultMessage()));
            attributes.addFlashAttribute("errors", errorMap);
            // 这里如果使用 转发 跳转,刷新页面的时候会提示重复提交 所以这里要使用重定向
            // 而重定向时 因为携带数据默认是在请求域中,重定向就获取不到了 携带数据就需要用到RedirectAttributes  不能使用 model
            return "redirect:http://auth.gulimall.com/register.html";
        }

        String code = userRegisterVo.getCode();
        String realCode = stringRedisTemplate.opsForValue().get(AuthServerConstant.SMS_CODE_CACHE_PREFIX + userRegisterVo.getEmail());

        if (StringUtils.isNotBlank(realCode)) {
            if (code.equals(realCode)) {
                // 验证码通过之后就没用了  直接删除验证码 保证一次请求只生效一次
                stringRedisTemplate.delete(AuthServerConstant.SMS_CODE_CACHE_PREFIX + userRegisterVo.getEmail());
                // 调用远程服务开始注册
                R register = memberFeignServer.register(userRegisterVo);
                if (register.getCode() == 0) {
                    if ((Boolean) register.get("isReg")) {
                        // 注册成功回到首页
                        return "redirect:http://auth.gulimall.com/login.html";
                    } else {
                        // 数据库插入错误
                        errorMap.put("errors", "账号注册异常,请重试或联系管理员");
                        attributes.addFlashAttribute("errors", errorMap);
                        return "redirect:http://auth.gulimall.com/register.html";
                    }
                } else {
                    errorMap.put("errors", JSONUtil.toBean(register.getData("msg"), String.class));
                    attributes.addFlashAttribute("errors", errorMap);
                    return "redirect:http://auth.gulimall.com/register.html";
                }
            } else {
                // 验证码错误
                errorMap = new HashMap<>();
                errorMap.put("code", "验证码错误");
                attributes.addFlashAttribute("errors", errorMap);
                return "redirect:http://auth.gulimall.com/register.html";
            }
        } else {
            errorMap = new HashMap<>();
            errorMap.put("code", "验证码错误");
            attributes.addFlashAttribute("errors", errorMap);
            return "redirect:http://auth.gulimall.com/register.html";
        }
    }

    @PostMapping("/login")
    public String login(UserLoginVo userLoginVo, RedirectAttributes attributes, HttpSession session) {
        R login = memberFeignServer.login(userLoginVo);
        if (login.getCode() == 0) {
            MemberResponseVo data = JSONUtil.toBean(login.getData(), MemberResponseVo.class);
            session.setAttribute(AuthServerConstant.LOGIN_USER, data);
            return "redirect:http://gulimall.com";
        } else {
            log.error("登录失败。。。。。。");
            Map<String, Object> errorMap = new HashMap<>();
            errorMap.put("msg", JSONUtil.toBean(login.getData("msg"), String.class));
            attributes.addFlashAttribute("errors", errorMap);
            return "redirect:http://auth.gulimall.com/login.html";
        }
    }

    // 如果已经登录了,再访问登录页就直接重定向到首页
    @GetMapping("/login.html")
    public String loginPage(HttpSession session) {
        if (session.getAttribute(AuthServerConstant.LOGIN_USER) != null) {
            return "redirect:http://gulimall.com";
        } else {
            return "login";
        }
    }


}
